import Warning from 'components/Markdown/Warning'
import Info from 'components/Markdown/Info'

export const meta = {
  title: 'MongoDB',
  position: 150
}

## Concepts

With the `1.22`-release, Prisma introduced a database connector for [MongoDB](https://www.mongodb.com/). MongoDB is a [document database](https://en.wikipedia.org/wiki/Document-oriented_database). Document databases stand in contrast to [relational databases](https://en.wikipedia.org/wiki/Relational_database) (RDBMS). 

Here is an overview of how the vocabulary differs between the two database types:

| RDBMS | MongoDB |
| --- | --- |
| Database | Database |
| Table | Collection |
| Row | Document |
| Index | Index |
| JOIN | Embedded Document _or_ Reference |
*Source: [MongoDB Documentation](https://www.mongodb.com/blog/post/thinking-documents-part-1)*

<Warning>

The [MongoDB](jgfm) database connector currently does not support ACID transactions. Learn more in [this](https://github.com/prisma/prisma/issues/3738) GitHub issue.

</Warning>

### Tables vs Collections

Relational databases store their data in **tables** that are defined within the database _schema_. Data is [normalized](https://en.wikipedia.org/wiki/Database_normalization) (_flattened_) and relations between tables are implemented using _keys_ as references between data records. A table contains a number of **rows** which represent _instances_ of the table.

MongoDB doesn't have the concept of tables. It is a _schemaless_ database that stores its data in unstructured **[collections](https://docs.mongodb.com/manual/reference/glossary/#term-collection)**. A collection contains a number of **[documents](https://docs.mongodb.com/manual/reference/glossary/#term-document)**. A document is the most basic unit of data in MongoDB and is stored in [BSON](http://bsonspec.org/) format. From a developer perspective, a document can be though of as a JSON object.

<Warning>

While MongoDB is a **schemaless** database, using it with Prisma does effectively impose a schema on it (in the form of the Prisma [datamodel](knun)). When writing data to MongoDB only through the Prisma API, Prisma guarantees that the data is consistent with the defined schema. 

**If you start writing to MongoDB directly, Prisma can not guarantee that the data in the database still adheres to the schema.**

</Warning>

### Relations

One of the biggest differences between document and relational databases is the way how _relations_ between data types are handled. 

While relational databases use [database normalization](https://en.wikipedia.org/wiki/Database_normalization) to store flat data records that reference each other via keys, document databases are able to store an object physically co-located to a related object within the same collection. The latter is called _embedding_ data (i.e. a document in a collection can have _embedded_ sub-documents/arrays which live inside the same collection).

With MongoDB, relations can be expressed either by _embedding_ data directly in a parent document or by using _references_. A good overview on the differences can be found in the MongoDB [documentation](https://www.mongodb.com/blog/post/thinking-documents-part-2#modeling-relationships-with-embedding-and-referencing). Prisma adopts the idea of _embedded_ types when modeling data for an underlying MongoDB.

Read [below](#data-modeling) to learn how relations in MongoDB can be modeled with Prisma.

### Migrations

Learn everything you need to know about migrations with MongoDB [here](asd1).

## Data modeling

### Embedded types

The MongoDB connector introduces the concept of _embedded types_. An embedded type ...

- ... always is annotated with the `@embedded` directive.
- ... always has (at least) one _parent type_.
- ... always is stored directly _within_ its parent type's [collection](https://docs.mongodb.com/manual/reference/glossary/#term-collection) in the underlying Mongo database (i.e. an embedded type never has its own collection).
- ... can not have unique fields (i.e. fields annotated with the `@unique` directive).
- ... can not have have a (back-)relation to its parent type (but it can have relations to other non-embedded types).
- ... can not be queried _directly_ using the Prisma API but only via _nested operations_ through the parent type. 
- ... can not be created, updated or deleted _directly_ using the Prisma API but only via _nested operations_ through the parent type. 

Here is an example of a datamodel where `Coordinates` is defined as an embedded type:

```graphql
type City {
  id: ID! @id
  name: String!
  coordinates: Coordinates
}

type Coordinates @embedded {
  latitude: Float!
  longitude: Float!
}
```

Here is an example of the data that's stored in the underlying MongoDB database based on this datamodel:

![](https://imgur.com/MX4jsQQ.png)

With this setup, it is _not_ possible to query any instances of `Coordinates` directly because `Coordinates` is an embedded type. `Coordinates` can only be queried via the `City` type. Similarly, you can not create, update or delete coordinates directly, instead you need to create, update or delete a `City` in order to perform such operation on an instance of `Coordinates`. 

> You can learn more about embedded types in the [specification](https://github.com/prisma/prisma/issues/2836).

### Link relations

With MongoDB, you can model relations in two ways:

- Using an [embedded type](#embedded-types) as explained above
- Using _references_ which are called _links_ in Prisma terminology

A _link relation_ with the MongoDB connector works in the way that:

- One side (A) of the relation stores the ID of the document on the other side (B), this is called an _inlined link_
- The other side (B) of the relation has _no reference_ at all to the document on the initial side (A)
- Each side of the relation is represented by its own collection in the underlying MongoDB, i.e. a link relation always spans accross multiple collections. 

You can denote the side of the relation that should store the ID using the `link` parameter of the `@relation` directive. In the following example, the `User` type stores the ID values of all the `Post` documents it's related to. A `Post` document however doesn't store any information about its `author` in the underlying Mongo database:

```graphql
type User {
  id: ID! @id
  name: String!
  posts: [Post!]! @relation(link: INLINE)
}

type Post {
  id: ID! @id
  title: String!
  author: User!
}
```

Here is an example of the data that's stored in the underlying MongoDB database based on this datamodel:

![](https://imgur.com/R7pTU1D.png)

While this approach enables querying for `Post` documents directly in the Prisma API (as opposed to embedded types which can only be queried through nested operations via their parent types), there are performance considerations when modeling relations this way.

Operations that go from a `Post` to a `User` via the `author` field will be more expensive. This is because the underlying `Post` objects don't know who their `author`s are and Prisma needs to filter all `User`s to find who the `author` of `Post` is.

### Directives

The MongoDB connector introduces a number of new directives and slight changes in the way how the datamodel behaves.

> If you are interested in this topic, you can follow the discussion around the [specification](https://github.com/prisma/prisma/issues/3408).

#### `@id`

In previous versions of the datamodel, there was only one way to assign a globally unique [ID](https://www.prisma.io/docs/data-model-and-migrations/data-model-knun/#id) to a model:

```graphql
type User {
  id: ID! @unique
}
```

If a field was defined like this in a previous version of the datamodel, Prisma would generate a globally unique ID and insert this ID as the value for the `id` field whenever a new record was being created.

The `@id` directive now gives more flexibility to developers since it can be applied to _any_ field in your datamodel (at most once per model), here is an example where the ID is stored in a field called `myID`:

```graphql
type User {
  myID: ID! @id
}
```

The `@id` directive always implies that the respective field is _unique_ (without the need to explicitly specify the `@unique` directive). Note that for the MongoDB connector, the `@id` directive is **required** on every model that's not [embedded](#embedded-types). 

> Learn more in the [specification](https://github.com/prisma/prisma/issues/3403).

#### `@createdAt` & `@updatedAt`

In previous versions of the datamodel, the [system fields](knun##system-fields:-createdat-and-updatedat) `createdAt` and `updatedAt` could be used to store when a record was created as well as when a record was las updated:

```graphql
type User {
  id: ID! @unique
  createdAt: DateTime!
  updatedAt: DateTime!
}
```

The new version of the datamodel removes the opinionation about how the fields need to be named. Instead, you can annonate any field of the `DateTime!` type with the `@createdAt` or `@updatedAt` directive to achieve the same functionality:

```graphql
type User {
  id: ID! @id
  created_at: DateTime! @createdAt
  updated_at: DateTime! @updatedAt
}
```

#### `@db`

The `@db(name: String!)` directive lets you be more explicit about mapping types and fields in your datamodel to the underlying database, i.e. it lets you specify a different name for a model in the API than the name that's used for the collection of the underlying database. This only works for non-embedded types, since embedded types don't have a collection that could be named.

Previously, Prisma would simply name the underlying table/collection after the model. The `name` argument of the directive defines the name of the collection or field that should be used in the database.

```graphql
type User @db(name: "user") {
  id: ID! @id
  name: String!
}

type Post @db(name: "post") {
  id: ID! @id
  stars: Int! @db(name: "starCount")
}
```

#### `@embedded`

The `@embedded` directive is used for _embedded types_. Find more info [above](#embedded-types).

## Limitations & Notes

- The `@rename` directive doesn't work with MongoDB
- Any field that's annotated with the `@id` directive is mapped to the [`_id`](https://docs.mongodb.com/manual/core/document/#the-id-field) field in MongoDB.
- The MongoDB connector does not support transactions. Learn more in [this](https://github.com/prisma/prisma/issues/3738) GitHub issue.

## Get started with a new database

### 1. Setup

Install the latest version of the Prisma CLI using the instructions [here](b5op#prisma-cli). Then run the following command to initialize a new Prisma service:

```bash copy
prisma init hello-mongo
```

This launches the interactive wizard that helps you configure Prisma. To test the new MongoDB connector, you need to select the following answers for the first two questions:

1. **Create new database**
1. **MongoDB**

As a last step in the wizard, you need to select your preferred language for the Prisma client that's used to read and write data against the Mongo database, we're choosing the **JavaScript Prisma Client** for this guide.

The Prisma CLI now created a `hello-mongo` directory for you which contains your project setup. The Docker Compose file is used to launch a Prisma server that's backed by a MongoDB. Navigate into the project directory and run the following command to start the Prisma server:

```bash copy
docker-compose up -d
```

> This might throw an error if you already have Prisma Docker containers running locally. In that case, you can [reset your Docker containers](rty1#hard-resetting-the-docker-environment).

You can verify that the Docker containers for Prisma and for your MongoDB have been started correctly by running `docker ps`. This should print something similar to this:

```
$ docker ps
CONTAINER ID        IMAGE                             COMMAND                  CREATED              STATUS              PORTS                      NAMES
5f3d8cc20699        mongo:3.6                         "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:27017->27017/tcp   hello-mongo_mongo_1
fc261a149740        prismagraphql/prisma:1.25    "/bin/sh -c /app/sta…"   About a minute ago   Up About a minute   0.0.0.0:4466->4466/tcp     hello-mongo_prisma_1
```

Once you're sure the Prisma server is running, you can deploy the Prisma service:

```bash copy
prisma deploy
```

Note that Prisma creates a new MongoDB [database](https://docs.mongodb.com/manual/core/databases-and-collections/#databases) for each combination of service _name_ and _stage_. Consider the following examples:

- Deploy to endpoint: `http://localhost:4466/hello-mongo/dev`
  - Service name: `hello-mongo`
  - Stage: `dev`
  - Result: Prisma creates a database called `hello-mongo_dev`
- Deploy to endpoint: `http://localhost:4466/hello-mongo/prod`
  - Service name: `hello-mongo`
  - Stage: `prod`
  - Result: Prisma creates a database called `hello-mongo_prod`
- Deploy to endpoint: `http://localhost:4466` (which is equivalent to `http://localhost:4466/default/default`)
  - Service name: `default`
  - Stage: `default`
  - Result: Prisma creates a database called  `default_default`

### 2. Use the Prisma client to read and write data

You can now play around with the generated Prisma client. Run the following commands to initialize a simple Node app:

```bash copy
npm init -y
npm install --save prisma-client-lib
touch index.js
```

Now add the following code to `index.js`:

```js copy
const { prisma } = require('./generated/prisma-client')

// A `main` function so that we can use async/await
async function main() {

  // Create a new user called `Alice`
  const newUser = await prisma.createUser({ name: 'Alice' })
  console.log(`Created new user: ${newUser.name} (ID: ${newUser.id})`)

  // Read all users from the database and print them to the console
  const allUsers = await prisma.users()
  console.log(allUsers)
}

main().catch(e => console.error(e))
```

You can run this script using the following command:

```bash copy
node index.js
```

This first creates a new document in the `User` collection and then retrieves all the documents from the `User` collection via the Prisma API.

### 3. Update the datamodel

Feel free to adjust the datamodel and explore some of the new features, for example:

```graphql copy
type User @db(name: "user") {
  id: ID! @id
  email: String @unique
  name: String!
  posts: [Post!]! @relation(link: INLINE)
}

type Post @db(name: "post") {
  id: ID! @id
  wasCreated: DateTime! @createdAt
  wasUpdated: DateTime! @updatedAt
  title: String!
  published: Boolean @default(value: false)
  author: User
  comments: [Comment!]!
}

type Comment @embedded {
  text: String!
  writtenBy: User!
}
```

Don't forget to update the Prisma API and regenerate your Prisma client after you changed `datamodel.prisma`:

```bash copy
prisma deploy
prisma generate
```

## Get started with an existing database

MongoDB is a _schemaless_ database, which means it is _possible_ to insert data of various structures into it. MongoDB never complains because a piece of inserted data doesn't adhere to some predefined, expected format. This is different from relational databases where data that's inserted needs to adhere to the predefined [database schema](https://en.wikipedia.org/wiki/Database_schema).

This changes when using MongoDB with Prisma. Prisma adds a "schema" (i.e. the Prisma [datamodel](knun)) on top of MongoDB.

Throughout your use of MongoDB with Prisma, when you're writing to the underlying MongoDB ...

- ... **only through the Prisma API**, it is guaranteed that the data that's stored in the database always adheres to the schema. This holds as long as you're only performing _additive_ changes to your Prisma datamodel. Once you start changing existing types and/or fields in the datamodel, you are responsible to keep the underlying data in sync with the datamodel because Prisma will never make changes to your underlying data and only perform additive migrations.
- ... **directly** (e.g. using the [Mongo shell](https://docs.mongodb.com/manual/mongo/)), it can not be guaranteed that the data that's stored in the database always adheres to the schema. In that case, you are responsible to ensure that the data that's written adheres to the schema.

<Warning>

Therefore, when starting out with an existing MongoDB, it is extremely important that the legacy data is consistent and that it can be modeled accurately as a Prisma datamodel. You can use the [`prisma introspect`](https://github.com/prisma/prisma/issues/3529) command to derive a datamodel from the data that's currently stored in your MongoDB.

</Warning>

### 1. Setup

When starting with an existing database, ensure you have the following information handy:

- Your [MongoDB connection string](https://docs.mongodb.com/manual/reference/connection-string/) which includes:
  - The **IP of the host machine** that's running the MongoDB server `mongod`, e.g. `localhost`.
  - The **port** where `mongod` is running on the host machine.
  - The **credentials** for a MongoDB [admin user](https://docs.mongodb.com/manual/tutorial/enable-authentication/#user-administrator).
  - The name of the **MongoDB [database](https://docs.mongodb.com/manual/core/databases-and-collections/#databases) where the admin user is stored**. (Typically called `admin`).
  - Whether the MongoDB is configured to use **SSL** or not.
- The name of the **MongoDB [database](https://docs.mongodb.com/manual/core/databases-and-collections/#databases) that you want to use with Prisma**.

Create a new directory for your Prisma service and add a Docker Compose file to it:

```bash copy
mkdir hello-mongo
cd hello-mongo
touch docker-compose.yml
```

Then add the following contents into the `docker-compose.yml`:

```yml copy
version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.25
    restart: always
    ports:
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: mongo
            uri: __MONGO_DB_CONNECTION_STRING__
            database: __MONGO_DB_DATABASE_NAME__
```

Replace both placeholders that are written in uppercase letters with the appropriate values, e.g.:

```yml
version: '3'
services:
  prisma:
    image: prismagraphql/prisma:1.25
    restart: always
    ports:
    - "4466:4466"
    environment:
      PRISMA_CONFIG: |
        port: 4466
        databases:
          default:
            connector: mongo
            uri: mongodb://myAdminUser:abc123@host.docker.internal:27017/admin
            database: mydb
```

> If you're running MongoDB on your local machine (without Docker but just by starting it manually using `mongod`), you need to set the [`host`](https://docs.mongodb.com/manual/reference/connection-string/#standard-connection-string-format) part of the connection string to `host.docker.internal` instead of `localhost` or `127.0.0.1`.

Once you're done, launch the Prisma server with the following command:

```bash copy
docker-compose up -d
```

The Prisma server is now connected to your MongoDB and runs on `http://localhost:4466`.

Next, you need to create your Prisma service configuration. Run the following command:

```bash copy
prisma init --endpoint http://localhost:4466
```

This creates the `prisma.yml` and `datamodel.prisma` files that make up your service configuration. 

Before you continue, add the following root property to your `prisma.yml`:

```yml
databaseType: document
```

### 2. Data modeling and ensuring data consistency

This step is very important when you're starting out with an existing MongoDB! The goal is to create a [datamodel](knun) that represents the data that's currently stored in the collections of your MongoDB. Next to modeling the data properly, you need to ensure that _all_ data in the database adheres to the datamodel that you specify - otherwise the Prisma API might throw errors at runtime.

Here are a few rules of thumb for modelling the data:

- Every collection in your MongoDB database should be represented by its own _model type_ in the Prisma datamodel.
- When a document inside a collection has _embedded_ documents, the structure of these embedded documents needs to be modeled as an an [embedded type](#embedded-type).
- A relation between documents of two separate collections needs to be modelled as a [link relation](#link-relations).
- Every model type needs to have exactly one field of type `ID!` that's annotated with the `@id` directive. This field gets mapped to the [MongoDB object ID](https://docs.mongodb.com/manual/core/document/#the-id-field) called `_id`.

<Info>

You can use [`prisma introspect`](https://github.com/prisma/prisma/issues/3529) to suggest a datamodel.

</Info>

### 3. Deploy the Prisma datamodel and generate the Prisma client

Once you are ready with defining your datamodel and have ensured that all currently stored data in the database adheres to the specified datamodel, you can start deploying the Prisma API.

For that, you first need to adjust the contents of your `prisma.yml`:

```yml copy
datamodel: datamodel.prisma
endpoint: http://localhost:4466
databaseType: document

generate:
  - generator: javascript-client
    output: ./generated
```

Next, run the following two commands to deploy your Prisma API and generate the Prisma client:

```bash copy
prisma deploy
prisma generate
```

### 4. Use the Prisma client to read and write data

The API of the generated Prisma client depends on your datamodel. For this example, we're assuming that your datamodel has a type `User` that's defined as follows:

```graphql
type User @db(name: "users") {
  id: ID! @id
  name: String!
}
```

The `@db` directive expresses that the underlying collection inside your MongoDB is called `users`.

Run the following commands to initialize a simple Node app:

```bash copy
npm init -y
npm install --save prisma-client-lib
touch index.js
```

Now add the following code to `index.js`:

```js copy
const { prisma } = require('./generated/prisma-client')

// A `main` function so that we can use async/await
async function main() {

  // Create a new user called `Alice`
  const newUser = await prisma.createUser({ name: 'Alice' })
  console.log(`Created new user: ${newUser.name} (ID: ${newUser.id})`)

  // Read all users from the database and print them to the console
  const allUsers = await prisma.users()
  console.log(allUsers)
}

main().catch(e => console.error(e))
```

You can run this script using the following command:

```bash copy
node index.js
```

This first creates a new document in the `users` collection and then retrieves all the documents from the `users` collection via the Prisma API.

## Using the Mongo shell

You can always connect to your MongoDB server using the [Mongo shell](https://docs.mongodb.com/manual/mongo/). Be careful with performing write-operations through the Mongo shell when using MongoDB with Prisma since you're loosing the guarantee that the stored data continues to adhere to the schema of the defined Prisma [datamodel](knun). It it recommended to only perform write-operations through the Prisma API to ensure data integrity.

When using MongoDB with Prisma following the setup in the ["Get started with a new database"-section](#get-started-with-a-new-database), you can use the Mongo shell to connect to the MongoDB server that's running with Docker. The following steps explain how to do so.

### 1. Installation

If you haven't done so before, you need to [install MongoDB](https://docs.mongodb.com/manual/installation/) on your machine. 

### 2. Launching the Mongo shell

Once it's installed, you can use the `mongo` command in your terminal to launch the shell.

### 3. Authenticating as an admin user

In the Docker Compose file that was created by the `prisma init` command, Prisma configured an _admin_ user with the following credentials:

- Username: `prisma`
- Password: `prisma`

To use the admin user, you first need to switch to the `admin` database that MongoDB creates by default. You can do so using the following command:

```bash copy
use admin
```

Now you can authenticate using the credentials that were set through the Docker Compose file:

```js copy
db.auth("prisma", "prisma")
```

You can verify that the authentication was successful by running `show dbs` which will print a list of the available databases, looking similar to this:

```
> show dbs
admin            0.000GB
config           0.000GB
default_default  0.000GB
local            0.000GB
prisma           0.000GB
```

### 4. Exploring the MongoDB of a Prisma service

Prisma creates a database that is named after the _name_ and the _stage_ of your Prisma service. These are the two path components at the end of your service's endpoint.

Here are two examples:

- A service with the endpoint `http://localhost:4466` (which is equivalent to `http://localhost:4466/default/default`) creates a database called `default_default`.
- A service with the endpoint `http://localhost:4466/hello-mongo/dev` creates a database called `hello-mongo_dev`

Switch to the database of your Prisma service, e.g. using this command:

```bash copy
use default_default
```

Now you can list all available collections with this command:

```bash copy
show collections
```

If you have a `users` collection available, you can run the following command to retrieve a single document from it:

```js copy
db.users.findOne()
```

Learn more about the Mongo shell API [here](https://docs.mongodb.com/manual/reference/method/js-collection/).

## PRISMA_CONFIG

`PRISMA_CONFIG` is the environment variable that needs to be provided to the Prisma Docker image specifying to which database the Prisma server should connect.

Here is the reference with some example values for what `PRISMA_CONFIG` looks like for MongoDB:

```yml
PRISMA_CONFIG: |
  port: 4466
  databases:
    default:
      connector: mongo
      uri: mongodb://myAdminUser:abc123@host.docker.internal:27017/admin
      database: mydb
```

Here is an overview of the available properties:

- `connector`: Specifies which database connector the Prisma server should use. Use `mongo` for MongoDB.
- `uri`: Your MongoDB [connection string](https://docs.mongodb.com/manual/reference/connection-string), i.e. the URL that can connect to your MongoDB server. Here's an overview of the information it needs to contain:
  - The connection protocol which specifies whether you want to use the [standard connection format](https://docs.mongodb.com/manual/reference/connection-string/#standard-connection-string-formats)  (`mongodb`) or the [DNS Seedlist Connection Format](https://docs.mongodb.com/manual/reference/connection-string/#dns-seedlist-connection-format) (`mongodb+srv`).
  - The credentials for a MongoDB [admin user](https://docs.mongodb.com/manual/tutorial/enable-authentication/#user-administrator) in the format `username@password`.
    - When starting with a **new database**, Prisma will create this user in the `admin` database.
    - When starting with an **existing database**, Prisma looks up the user with these credentials in the [`authSource`](https://docs.mongodb.com/manual/reference/connection-string/#authentication-options) database (see next property).
  - The IP/hostname of the host machine that's running the MongoDB server `mongod`, e.g. `localhost` (or `host.docker.internal` if you're running MongDB via Docker).
  - The port where `mongod` is running on the host machine. ([Default](https://docs.mongodb.com/manual/reference/default-mongodb-port/): `27017`).
  - The ["authentication source"](https://docs.mongodb.com/manual/reference/connection-string/#authentication-options), i.e.  MongoDB [database](https://docs.mongodb.com/manual/core/databases-and-collections/#databases) where the admin user is stored. (Default: `admin`).
  - A boolean that specifies whether the connection to the MongoDB should use [SSL](https://docs.mongodb.com/manual/reference/connection-string/#urioption.ssl). (Default depends on the connection protocol. Default for `mongodb+rsv`: `true`. Default for `mongodb`: `false`).
- `database`: The MongoDB [database](https://docs.mongodb.com/manual/core/databases-and-collections/#databases) you want to connect to. This property is only required if you want to connect to an **existing database**, otherwise it can be omitted.
- `rawAccess`: Specifies whether the [`executeRaw`](qwe4) mutation will be enabled in the Prisma API. The MongoDB connector currently doesn't support raw access, so you need to set this to `false` or omit it.
